package com.nineclock.approve.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.nineclock.approve.dto.*;
import com.nineclock.approve.mapper.ApproveDefinitionMapper;
import com.nineclock.approve.pojo.ApproveDefinition;
import com.nineclock.approve.service.ActivitiService;
import com.nineclock.approve.service.ApproveDefinitionService;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.threadlocal.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.common.utils.JsonUtils;
import com.nineclock.common.utils.UUIDUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ApproveDefinitionServiceImpl implements ApproveDefinitionService {

    @Autowired
    ApproveDefinitionMapper approveDefinitionMapper;

    @Autowired
    ActivitiService activitiService;

    /**
     * 查询流程定义列表
     *
     * @return
     */
    @Override
    public List<ApproveGroupDefinitionDto> queryApproveGroupDefinition() {
        ArrayList<ApproveGroupDefinitionDto> approveGroupDefinitionDtos = new ArrayList<>();
        LambdaQueryWrapper<ApproveDefinition> approveDefinitionLambdaQueryWrapper = new LambdaQueryWrapper<>();
        approveDefinitionLambdaQueryWrapper.eq(ApproveDefinition::getCompanyId, CurrentUserHolder.get().getCompanyId());
        approveDefinitionLambdaQueryWrapper.eq(ApproveDefinition::getIsValid, "1");

        List<ApproveDefinition> approveDefinitions = approveDefinitionMapper.selectList(approveDefinitionLambdaQueryWrapper);

        if (CollectionUtil.isNotEmpty(approveDefinitions)) {
            Map<String, List<ApproveDefinition>> map = approveDefinitions.stream().collect(Collectors.groupingBy(ApproveDefinition::getGroupType));

            for (String s : map.keySet()) {
                ApproveGroupDefinitionDto approveGroupDefinitionDto = new ApproveGroupDefinitionDto();
                approveGroupDefinitionDto.setGroupType(s);
                approveGroupDefinitionDto.setDefinitionList(map.get(s));
                approveGroupDefinitionDtos.add(approveGroupDefinitionDto);
            }
        }
        return approveGroupDefinitionDtos;
    }

    /**
     * 保存或修改审批流程定义
     *
     * @param approveDefinitionSaveDto
     */
    @Override
    public void saveApproveDefinition(ApproveDefinitionSaveDto approveDefinitionSaveDto) {

        ApproveDefinitionBaseDataDto baseData = approveDefinitionSaveDto.getBaseData();
        if (baseData == null) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        ApproveDefinition definition = null;
        if (StrUtil.isEmpty(baseData.getId())) { //新增
            definition = BeanHelper.copyProperties(baseData, ApproveDefinition.class, "allowUserJson");

            List<AllowUserObjDto> allowUserJson = baseData.getAllowUserJson();
            definition.setAllowUserJson(JsonUtils.toString(allowUserJson));
            List<ApproveDefinitionTableDataDto> tableData = approveDefinitionSaveDto.getTableData();
            definition.setFlowJson(JsonUtils.toString(tableData));

            definition.setTableName("flow_" + UUIDUtils.getUUID());

            List<ColumnObjDto> columnObjDtos = expandFieldKey(approveDefinitionSaveDto);
            definition.setColumns(JsonUtils.toString(columnObjDtos));

            JSONArray jsonArray = JSONUtil.parseArray(approveDefinitionSaveDto.getFlowData());
            expandParamWithNodeKey(jsonArray);
            definition.setFlowJson(JsonUtils.toString(jsonArray));

            definition.setDataFrom("1");
            definition.setIsValid("1");
            definition.setCompanyId(CurrentUserHolder.get().getCompanyId() + "");

            definition.setCreateTime(new Date());
            definition.setUpdateTime(new Date());

            approveDefinitionMapper.insert(definition);

            //保存 审批流程 到 activiti中
            activitiService.deployProcessToActiviti(definition);
        } else {
            //更新 -----------> ID 不存在的情况下 ;
            // 根据ID查询流程定义对象
            definition = approveDefinitionMapper.selectById(baseData.getId());

            BeanUtil.copyProperties(baseData, definition, "allowUserJson");//基础数据赋值

            definition.setAllowUserJson(JsonUtils.toString(baseData.getAllowUserJson()));//赋值允许操作用户

            definition.setFormJson(JsonUtils.toString(approveDefinitionSaveDto.getTableData()));//赋值表单信息


            //需要将所有的表单信息, 记录下来并拓展参数 fieldKey, 字段主键
            List<ColumnObjDto> columns = expandFieldKey(approveDefinitionSaveDto);
            definition.setColumns(JsonUtils.toString(columns));


            //传递的流程数据中, 如果不包含nodeKey属性, 需要扩充
            JSONArray jsonArray = JSONUtil.parseArray(approveDefinitionSaveDto.getFlowData());
            expandParamWithNodeKey(jsonArray);
            definition.setFlowJson(JSONUtil.toJsonStr(jsonArray));

            //更新数据
            approveDefinitionMapper.updateById(definition);

            //更新到activiti中
            //删除activiti中的审批流程
            activitiService.dropProcessFromActiviti(definition);
            //部署审批流程到activiti
            activitiService.deployProcessToActiviti(definition);
        }
    }

    /**
     * 流程定义: 根据ID查询
     *
     * @param id
     * @return
     */
    @Override
    public ApproveDefinitionResultDto queryById(String id) {
        ApproveDefinitionResultDto approveDefinitionResultDto = new ApproveDefinitionResultDto();
        ApproveDefinition definition = approveDefinitionMapper.selectById(id);
        ApproveDefinitionBaseDataDto allowUserJson = BeanHelper.copyProperties(definition, ApproveDefinitionBaseDataDto.class, "allowUserJson");
        List<AllowUserObjDto> allowUserObjDtos = JsonUtils.toList(definition.getAllowUserJson(), AllowUserObjDto.class);
        allowUserJson.setAllowUserJson(allowUserObjDtos);

        List<ApproveDefinitionTableDataResultDto> tableList = null;
        String formJson = definition.getFormJson();
        if (StrUtil.isNotEmpty(formJson)) {
            tableList = JsonUtils.toList(formJson, ApproveDefinitionTableDataResultDto.class);
        }
        String flowJson = definition.getFlowJson();

        approveDefinitionResultDto.setBaseData(allowUserJson).setTableData(tableList).setFlowData(flowJson);
        return approveDefinitionResultDto;

    }

    /**
     * 扩充参数 : fieldKey
     *
     * @param approveDefinitionDto
     * @return
     */
    private List<ColumnObjDto> expandFieldKey(ApproveDefinitionSaveDto approveDefinitionDto) {
        List<ColumnObjDto> columns = new ArrayList<>();

        for (ApproveDefinitionTableDataDto tableData : approveDefinitionDto.getTableData()) {
            if (StrUtil.isEmpty(tableData.getFieldKey())) {
                tableData.setFieldKey(UUIDUtils.getUUID());
            }

            columns.add(new ColumnObjDto(tableData.getFieldKey(), tableData.getLab(), tableData.getTitle(), "1"));
        }
        return columns;
    }

    private void expandParamWithNodeKey(JSONArray jsonArray) {
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonNode = (JSONObject) jsonArray.get(i);

            String nodeKey = jsonNode.getStr("nodeKey");
            if (StrUtil.isEmpty(nodeKey)) {
                jsonNode.put("nodeKey", UUIDUtils.getUUID());
            }

            //处理网关节点的内部节点 nodeKey
            String type = jsonNode.getStr("type");
            if ("condition".equals(type)) {

                JSONArray batchArray = (JSONArray) jsonNode.get("node");
                if (batchArray != null && batchArray.size() > 0) {

                    for (int j = 0; j < batchArray.size(); j++) {
                        JSONArray innerArray = (JSONArray) batchArray.get(j);

                        if (innerArray != null && innerArray.size() > 0) {
                            for (int k = 0; k < innerArray.size(); k++) {
                                JSONObject node = (JSONObject) innerArray.get(k);
                                if (!node.containsKey("nodeKey")) {
                                    node.put("nodeKey", UUIDUtils.getUUID());
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
